<template>
  <div class="t-dropdown">
    <div class="t-dropdown__btn-wrapper" ref="btnWrapper" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave" @click="handleClick"><slot name="btn"></slot></div>
    <transition :name="transition">
      <div class="t-dropdown__menu-wrapper" ref="menuWrapper" :placement="placement" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave" v-show="currentVisible" v-transfer>
        <slot name="list"></slot>
      </div>
    </transition>
  </div>
</template>

<script>
  import Popper from 'popper.js';
  import { oneOf } from './utils/assist';
  import transfer from '../directives/transfer';
  
  export default {
    name: 't-dropdown',
    directives: { transfer },
    props: {
      placement: {
        validator(value) {
          return oneOf(value, ['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end', 'right', 'right-start', 'right-end']);
        },
        default: 'bottom',
      },
      visible: {
        type: Boolean,
        default: false,
      },
      trigger: {
        type: String,
        default: 'click',
      },
    },
    computed: {
      transition() {
        return ['bottom-start', 'bottom', 'bottom-end'].indexOf(this.placement) > -1 ? 'slide-up' : 'fade';
      },
    },
    data() {
      return {
        popper: null,
        currentVisible: this.visible,
      };
    },
    watch: {
      visible(val) {
        this.currentVisible = val;
      },
      currentVisible(val) {
        if (val) {
          this.updatePop();
        } else {
          this.destroyPop();
        }
      },
    },
    methods: {
      handleClick() {
      },
      handleMouseEnter() {
        if (this.timeout) window.clearTimeout(this.timeout);
        this.timeout = window.setTimeout(() => {
          this.currentVisible = true;
        }, 250);
        return true;
      },
      handleMouseLeave() {
        if (this.timeout) {
          window.clearTimeout(this.timeout);
          this.timeout = setTimeout(() => {
            this.currentVisible = false;
          }, 150);
        }
        return true;
      },
      onClickOutside() {
        this.handleClose();
      },
      handleClose() {
        this.currentVisible = false;
      },
      updatePop() {
        if (this.popper) {
          this.$nextTick(() => {
            this.popper.update();
          });
        } else {
          this.$nextTick(() => {
            this.popper = new Popper(this.$refs.btnWrapper, this.$refs.menuWrapper, {
              placement: 'bottom',
              forceAbsolute: true,
              gpuAcceleration: true,
              boundariesPadding: 0,
              boundariesElement: 'body',
            });
          });
        }
      },
      resetTransformOrigin(popper) {
        const placementMap = { top: 'bottom', bottom: 'top' };
        /* eslint-disable no-underscore-dangle */
        const placement = popper._popper.getAttribute('x-placement').split('-')[0];
        const origin = placementMap[placement];
        /* eslint-disable no-underscore-dangle */
        popper._popper.style.transformOrigin = `center ${origin}`;
      },
      destroyPop() {
        if (this.popper) {
          setTimeout(() => {
            if (this.popper) {
              this.popper.destroy();
              this.popper = null;
            }
          }, 300);
        }
      },
    },
    mounted() {
      this.$on('on-click', (e) => {
        const $parent = this.hasParent();
        if ($parent) $parent.$emit('on-click', e);
      });
      this.$on('on-hover-click', () => {
        const $parent = this.hasParent();
        if ($parent) {
          this.$nextTick(() => {
            if (this.trigger === 'custom') return false;
            this.currentVisible = false;
            return true;
          });
          $parent.$emit('on-hover-click');
        } else {
          this.$nextTick(() => {
            if (this.trigger === 'custom') return false;
            this.currentVisible = false;
            return true;
          });
        }
      });
      this.$on('on-haschild-click', () => {
        this.$nextTick(() => {
          if (this.trigger === 'custom') return false;
          this.currentVisible = true;
          return true;
        });
        const $parent = this.hasParent();
        if ($parent) $parent.$emit('on-haschild-click');
      });
    },
  };
</script>